package com.peza.bikelog.business.service.impl;

import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.xml.datatype.XMLGregorianCalendar;

import com.peza.bikelog.business.service.GarminService;
import com.peza.bikelog.business.service.PolarService;
import com.peza.bikelog.common.domain.garmin.ActivityLapT;
import com.peza.bikelog.common.domain.garmin.ActivityT;
import com.peza.bikelog.common.domain.garmin.HeartRateInBeatsPerMinuteT;
import com.peza.bikelog.common.domain.garmin.HeartRateValueT;
import com.peza.bikelog.common.domain.garmin.TrackT;
import com.peza.bikelog.common.domain.garmin.TrackpointT;
import com.peza.bikelog.common.domain.garmin.TrainingCenterDatabaseT;
import com.peza.bikelog.common.domain.polar.HrmData;
import com.peza.bikelog.common.domain.polar.HrmHrData;
import com.peza.bikelog.common.util.FileProcessor;
import com.peza.bikelog.common.util.TrainingCenterFactory;
import com.peza.bikelog.common.util.Util;
import com.peza.bikelog.common.util.XmlConverter;
import com.peza.bikelog.common.util.XmlConverterImpl;

public class GarminServiceImpl implements GarminService{

	private XmlConverter xc = new XmlConverterImpl();
	
	private PolarService polarService = new PolarServiceImpl();
	
	private TrainingCenterFactory factory = TrainingCenterFactory.getInstance();
	
	private FileProcessor filer = FileProcessor.getInstance();
	
	private Util util = Util.getInstance();
	
	private static int counter = 0;
	
	@Override
	public TrainingCenterDatabaseT createActivity(String filename) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public TrainingCenterDatabaseT matchGarminWithPolar(String inputFile, String polarDir) {
		File file = new File(inputFile);
		String garmin = file.getName();
		System.out.println("Garmin source name : ["+garmin+"]");
		//garmin = 200801071-exported.tcx
		//polar = 08010701.hrm
		
		String polarname = garmin.substring(2,8) + "0" + garmin.substring(8,9) + ".hrm";		
		String polarYearDir = "20"+garmin.substring(2,4)+"/";
		
		String primaryPolar = polarDir+polarYearDir+"exports/"+polarname;
		String secondaryPolar = polarDir+polarYearDir+polarname;
		
		System.out.println("Polar search for : ["+primaryPolar+"]");
		
		File polarFile = new File(primaryPolar);
		File polarFile2 = new File(secondaryPolar);
				
		if (polarFile.exists()){
			return mergeGarminWithPolar(file, polarFile);
		} else if (polarFile2.exists()){
			return mergeGarminWithPolar(file, polarFile2);
		} else {
			System.out.println("Polar file not found");

		}
		return null;
		
	}
	
	@Override
	public TrainingCenterDatabaseT mergeGarminWithPolar(File garminFile, File polarFile) {
		
		TrainingCenterDatabaseT garmin = xc.createObject(garminFile, TrainingCenterDatabaseT.class);
		HrmData polar = polarService.getPolarData(polarFile);
		
		Integer garminDistanceMeters = 0;
		Integer garminDurationSecs = 0;

		for (ActivityLapT lap : garmin.getActivities().getActivity().get(0).getLap()){
			garminDistanceMeters += util.convertToInt(lap.getDistanceMeters());
			garminDurationSecs += util.convertToInt(lap.getTotalTimeSeconds());
		}
		
		Integer polarDistanceMeters = polar.getTrip().getDistance()*100;
		Long polarDurationSecs =  polar.getTrip().getTotalTime();
		
//		int meterDev = garminDistanceMeters - polarDistanceMeters;
//		float percentage = (float)meterDev * 100 / (float)garminDistanceMeters;
//		System.out.println("meters deviation : ["+meterDev+"]");
		
		long durDev = garminDurationSecs - polarDurationSecs;
		float percentage = (float)durDev * 100 / (float)garminDurationSecs;
		
		if (percentage < 10 && percentage > -10){
			System.out.println("match : ["+garminDurationSecs+"-"+polarDurationSecs+"] >> " + percentage);
			alignGarmin(garmin,percentage,(polarDurationSecs*1000));
			mergeLaps(garmin,polar);
			counter++;
		
		} else {
			System.err.println("no match, too much deviation : ["+garminDistanceMeters+"-"+polarDistanceMeters+"] >> " + percentage);
		}

		return null;
		
	}

	
	@Override
	public void separateActivities(String path, String inputfile, String outDir, String prefixFilter) {
		
		File dbFile = FileProcessor.getInstance().getFile(path+inputfile);
		System.out.println("Located database file : ["+inputfile+"]");

		TrainingCenterDatabaseT tcx = xc.createObject(dbFile, TrainingCenterDatabaseT.class);
		System.out.println("Created TCX database object...");
		TrainingCenterDatabaseT tc2 = null;
		for (ActivityT act : tcx.getActivities().getActivity()){
			System.out.println("Found activity : ["+act.getId().toString()+"]");
			XMLGregorianCalendar name = act.getId();			
			String filename = getFileName(name.toString());
			if (prefixFilter != null && filename.startsWith(prefixFilter)){
				tc2 = factory.createActivity(act, tcx.getAuthor());
				System.out.println("Created activity object...");
				byte [] contents = xc.createXml(tc2, TrainingCenterDatabaseT.class);
				String outcome = filer.writeFile(new String (contents), outDir, filename, ".tcx");
				System.out.println("Written activity to file : ["+outcome+"]");
			}	
		}	
		System.out.println("Separation done...");
	}
	

	private TrainingCenterDatabaseT alignGarmin(TrainingCenterDatabaseT garmin, float percentage, long polardur){
		
		List <TrackpointT> trackpoints = new ArrayList<TrackpointT>();
		
		for (ActivityLapT lap : garmin.getActivities().getActivity().get(0).getLap()){
			List <TrackT> lapTracks = lap.getTrack();
			for (TrackT track : lapTracks){
				trackpoints.addAll(track.getTrackpoint());
			}			
		}
		
		TrackpointT firsttp = trackpoints.get(0);
		XMLGregorianCalendar time = firsttp.getTime();
		long revdiff = 0;
		for (TrackpointT tp : trackpoints){
			XMLGregorianCalendar tpt = tp.getTime();
			long diff = timeDifference(time, tpt);
			revdiff = (long) ((float)diff*(100+percentage)/100);
			System.out.println("elapsed  >> real : ["+diff+"]  \t revised : ["+revdiff+"]");
		}

		System.out.println("garmin duration : ["+revdiff+"] \t polar duration : ["+polardur+"]");
		
		return garmin;
		
	}
	
	
	
	
	private void mergeLaps(TrainingCenterDatabaseT garmin, HrmData polar){
		
		// add all the trackpoints to  a list...
		List <TrackpointT> trackpoints = new ArrayList<TrackpointT>();
		
		for (ActivityLapT lap : garmin.getActivities().getActivity().get(0).getLap()){
			List <TrackT> lapTracks = lap.getTrack();
			for (TrackT track : lapTracks){
				trackpoints.addAll(track.getTrackpoint());
			}			
		}
		
		TrackpointT ftp = trackpoints.get(0);
		XMLGregorianCalendar time = ftp.getTime();
		int segment = 0;
		int interval = util.convertToInt(polar.getParams().getInterval());
		
		System.out.println("polar interval : " + polar.getParams().getInterval());
		System.out.println("polar samples : " + polar.getHrData().getSamples().size());
		System.out.println("garmin samples : " + trackpoints.size());
		
		for (TrackpointT tp : trackpoints){
			XMLGregorianCalendar tpt = tp.getTime();
			long diff = timeDifference(time, tpt);
			
			segment = (int) (diff/interval);
			
			//System.out.println(tp.getTime().toString() + " : segment["+segment+"] -- hr[" +polar.getHrData().getSamples().get(segment).getBpm()+"]");

//			if (tp.getSensorState() == null || tp.getSensorState().equals("Absent")){
//				HeartRateInBeatsPerMinuteT bpm = new HeartRateInBeatsPerMinuteT();
//				HrmHrData.Sample sample = polar.getHrData().getSamples().get(segment);
//				bpm.setValue((short)sample.getBpm());
//				tp.setHeartRateBpm(bpm);
//				System.out.println(diff +" : "+ segment +" : "+ bpm.getValue());
//			}
		}
		
	}
	
	
	
	/** returns difference in seconds between two timestamps **/
	private long timeDifference(XMLGregorianCalendar first, XMLGregorianCalendar second){
		long days = (second.getDay()-first.getDay()) * 1000 *60 *60 * 24 ;         //x1000 x60 x24
		long hours = (second.getHour() - first.getHour()) * 1000 *60 *60;    //x1000 x60 x60
		long mins = (second.getMinute() - first.getMinute())  * 1000 *60; //x1000 x60
		long secs = (second.getSecond() - first.getSecond())  * 1000; //x1000
		long mills = (second.getMillisecond() - first.getMillisecond());
		
		long out = days+hours+mins+secs+mills;
		return out;
		
		
	}
	
	
	private static String getFileName(String input) {
		String year = input.substring(0,4);
		String month = input.substring(5,7);
		String day = input.substring(8,10);
		String hour = input.substring(11,13);
		String min = input.substring(14,16);
		
		return year+month+day;
	}

	
}
